@@ -4,6 +4,7 @@ from django.conf.urls import url |
||
4 | 4 |
|
5 | 5 |
from api import admin_views, mini_views, oauth_views, pack_views |
6 | 6 |
from pay import views as pay_views |
7 |
+from live import views as live_views |
|
7 | 8 |
|
8 | 9 |
|
9 | 10 |
urlpatterns = [ |
@@ -21,6 +22,14 @@ urlpatterns += [ |
||
21 | 22 |
url(r'^pay/wx/notify_url$', pay_views.wx_notify_url_api, name='wx_notify_url_api'), # 支付异步通知回调地址 |
22 | 23 |
] |
23 | 24 |
|
25 |
+#直播相关 |
|
26 |
+urlpatterns += [ |
|
27 |
+ url(r'^live/goods/detail$', live_views.room_goods_detail, name='room_goods_detail'), |
|
28 |
+ url(r'^live/order/create$', live_views.live_order_create, name='live_order_create'), |
|
29 |
+ url(r'^live/order/cancel$', live_views.live_order_cancel, name='live_order_cancel'), |
|
30 |
+ url(r'^live/pay/notify_url$', live_views.notify_url_api, name='notify_url_api'), |
|
31 |
+] |
|
32 |
+ |
|
24 | 33 |
urlpatterns += [ |
25 | 34 |
url(r'^admin/login$', admin_views.login, name='login'), |
26 | 35 |
|
@@ -61,6 +61,7 @@ INSTALLED_APPS = [ |
||
61 | 61 |
'kol', |
62 | 62 |
'pay', |
63 | 63 |
'simditor', |
64 |
+ 'live', |
|
64 | 65 |
] |
65 | 66 |
|
66 | 67 |
MIDDLEWARE = [ |
@@ -0,0 +1,30 @@ |
||
1 |
+from django.contrib import admin |
|
2 |
+ |
|
3 |
+from live.models import RoomGoodsInfo, RoomInfo, AnchorInfo, liveGoodsInfo, RoomOrderInfo |
|
4 |
+ |
|
5 |
+ |
|
6 |
+class AnchorInfoAdmin(admin.ModelAdmin): |
|
7 |
+ list_display = ('anchor_id', 'unionid', 'anchor_name', 'anchor_avatar', 'openid', 'status', 'created_at', 'updated_at') |
|
8 |
+ |
|
9 |
+ |
|
10 |
+class RoomInfoAdmin(admin.ModelAdmin): |
|
11 |
+ list_display = ('room_id', 'name', 'live_status', 'start_time', 'end_time', 'cover_img', 'share_img', 'anchor_id', 'anchor_name', 'goods', 'status', 'created_at', 'updated_at') |
|
12 |
+ |
|
13 |
+ |
|
14 |
+class liveGoodsInfoAdmin(admin.ModelAdmin): |
|
15 |
+ list_display = ('goods_id', 'wx_goods_id', 'audit_id', 'audit_status', 'goods_img', 'coverImgUrl', 'name', 'price_type', 'price', 'price2', 'url', 'status', 'created_at', 'updated_at') |
|
16 |
+ |
|
17 |
+ |
|
18 |
+class RoomGoodsInfoAdmin(admin.ModelAdmin): |
|
19 |
+ list_display = ('room_id', 'anchor_id', 'goods_id', 'inventory', 'sale_infos', 'status', 'created_at', 'updated_at') |
|
20 |
+ |
|
21 |
+class RoomOrderInfoAdmin(admin.ModelAdmin): |
|
22 |
+ list_display = ('order_id', 'anchor_id', 'room_id', 'goods_id', 'share_openid', 'user_id', 'total_fee', 'name', 'phone', 'address', 'tracking_number', 'pay_status', 'status', 'created_at', 'updated_at') |
|
23 |
+ readonly_fields_exclude = ('tracking_number', ) |
|
24 |
+ |
|
25 |
+ |
|
26 |
+admin.site.register(AnchorInfo, AnchorInfoAdmin) |
|
27 |
+admin.site.register(RoomInfo, RoomInfoAdmin) |
|
28 |
+admin.site.register(liveGoodsInfo, liveGoodsInfoAdmin) |
|
29 |
+admin.site.register(RoomGoodsInfo, RoomGoodsInfoAdmin) |
|
30 |
+admin.site.register(RoomOrderInfo, RoomOrderInfoAdmin) |
@@ -0,0 +1,5 @@ |
||
1 |
+from django.apps import AppConfig |
|
2 |
+ |
|
3 |
+ |
|
4 |
+class LiveConfig(AppConfig): |
|
5 |
+ name = 'live' |
@@ -0,0 +1,136 @@ |
||
1 |
+# Generated by Django 2.2.12 on 2020-05-15 14:51 |
|
2 |
+ |
|
3 |
+from django.db import migrations, models |
|
4 |
+import django_models_ext.fileext |
|
5 |
+import jsonfield.fields |
|
6 |
+import shortuuidfield.fields |
|
7 |
+ |
|
8 |
+ |
|
9 |
+class Migration(migrations.Migration): |
|
10 |
+ |
|
11 |
+ initial = True |
|
12 |
+ |
|
13 |
+ dependencies = [ |
|
14 |
+ ] |
|
15 |
+ |
|
16 |
+ operations = [ |
|
17 |
+ migrations.CreateModel( |
|
18 |
+ name='AnchorInfo', |
|
19 |
+ fields=[ |
|
20 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
21 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
22 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
23 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
24 |
+ ('anchor_id', shortuuidfield.fields.ShortUUIDField(blank=True, editable=False, help_text='主播唯一标识', max_length=22, unique=True)), |
|
25 |
+ ('unionid', models.CharField(blank=True, help_text='微信 Unionid', max_length=32, unique=True, verbose_name='unionid')), |
|
26 |
+ ('openid', models.CharField(blank=True, help_text='微信 Openid', max_length=32, unique=True, verbose_name='openid')), |
|
27 |
+ ('anchor_name', models.CharField(blank=True, db_index=True, help_text='主播姓名', max_length=255, verbose_name='anchor_name')), |
|
28 |
+ ('anchor_avatar', models.CharField(blank=True, db_index=True, help_text='主播头像', max_length=255, verbose_name='anchor_avatar')), |
|
29 |
+ ], |
|
30 |
+ options={ |
|
31 |
+ 'verbose_name': '主播信息', |
|
32 |
+ 'verbose_name_plural': '主播信息', |
|
33 |
+ }, |
|
34 |
+ ), |
|
35 |
+ migrations.CreateModel( |
|
36 |
+ name='liveGoodsInfo', |
|
37 |
+ fields=[ |
|
38 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
39 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
40 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
41 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
42 |
+ ('goods_id', shortuuidfield.fields.ShortUUIDField(blank=True, editable=False, help_text='商品ID', max_length=22, unique=True)), |
|
43 |
+ ('wx_goods_id', models.CharField(blank=True, db_index=True, help_text='微信商品ID', max_length=255, verbose_name='wx_goods_id')), |
|
44 |
+ ('audit_id', models.CharField(blank=True, db_index=True, help_text='审核单ID', max_length=255, verbose_name='anchor_name')), |
|
45 |
+ ('audit_status', models.IntegerField(blank=True, db_index=True, default=0, help_text='审核状态', verbose_name='audit_status')), |
|
46 |
+ ('goods_img', models.ImageField(help_text='商品图', upload_to=django_models_ext.fileext.upload_path, verbose_name='goods_img')), |
|
47 |
+ ('coverImgUrl', models.CharField(blank=True, db_index=True, help_text='微信mediaID', max_length=255, verbose_name='anchor_name')), |
|
48 |
+ ('name', models.CharField(blank=True, db_index=True, help_text='商品', max_length=34, verbose_name='name')), |
|
49 |
+ ('price_type', models.IntegerField(db_index=True, help_text='价格类型', verbose_name='price_type')), |
|
50 |
+ ('price', models.IntegerField(help_text='price', verbose_name='price')), |
|
51 |
+ ('price2', models.IntegerField(help_text='price2', verbose_name='price2')), |
|
52 |
+ ('url', models.CharField(blank=True, db_index=True, help_text='小程序商品路径', max_length=255, verbose_name='url')), |
|
53 |
+ ], |
|
54 |
+ options={ |
|
55 |
+ 'verbose_name': '直播商品库', |
|
56 |
+ 'verbose_name_plural': '直播商品库', |
|
57 |
+ }, |
|
58 |
+ ), |
|
59 |
+ migrations.CreateModel( |
|
60 |
+ name='RoomGoodsInfo', |
|
61 |
+ fields=[ |
|
62 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
63 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
64 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
65 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
66 |
+ ('room_id', models.CharField(db_index=True, help_text='房间唯一标识', max_length=32, unique=True, verbose_name='room_id')), |
|
67 |
+ ('anchor_id', models.CharField(blank=True, help_text='主播唯一标识', max_length=32, unique=True, verbose_name='anchor_id')), |
|
68 |
+ ('goods_id', models.CharField(blank=True, help_text='商品ID', max_length=32, unique=True, verbose_name='goods_id')), |
|
69 |
+ ('inventory', models.IntegerField(default=0, help_text='直播间库存数量', verbose_name='inventory')), |
|
70 |
+ ('sale_infos', jsonfield.fields.JSONField(blank=True, default=[], help_text='直播间商品销售信息', verbose_name='sale_infos')), |
|
71 |
+ ], |
|
72 |
+ options={ |
|
73 |
+ 'verbose_name': '直播间商品信息', |
|
74 |
+ 'verbose_name_plural': '直播间商品信息', |
|
75 |
+ }, |
|
76 |
+ ), |
|
77 |
+ migrations.CreateModel( |
|
78 |
+ name='RoomInfo', |
|
79 |
+ fields=[ |
|
80 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
81 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
82 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
83 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
84 |
+ ('room_id', models.CharField(db_index=True, help_text='房间唯一标识', max_length=32, unique=True, verbose_name='anchor_id')), |
|
85 |
+ ('name', models.CharField(blank=True, db_index=True, help_text='直播房间名', max_length=255, verbose_name='name')), |
|
86 |
+ ('live_status', models.IntegerField(db_index=True, help_text='直播状态', verbose_name='live_status')), |
|
87 |
+ ('start_time', models.IntegerField(db_index=True, help_text='直播计划开始时间', verbose_name='start_time')), |
|
88 |
+ ('end_time', models.IntegerField(db_index=True, help_text='直播计划结束时间', verbose_name='end_time')), |
|
89 |
+ ('cover_img', models.ImageField(help_text='直播间背景墙', upload_to=django_models_ext.fileext.upload_path, verbose_name='cover_img')), |
|
90 |
+ ('anchor_name', models.CharField(blank=True, db_index=True, help_text='主播名称', max_length=255, verbose_name='anchor_name')), |
|
91 |
+ ('anchor_img', models.ImageField(help_text='分享卡片图片', upload_to=django_models_ext.fileext.upload_path, verbose_name='cover_img')), |
|
92 |
+ ('anchor_id', models.CharField(help_text='主播唯一标识', max_length=32, unique=True, verbose_name='anchor_id')), |
|
93 |
+ ('goods', jsonfield.fields.JSONField(blank=True, default=[], help_text='商品销售信息', verbose_name='goods')), |
|
94 |
+ ], |
|
95 |
+ options={ |
|
96 |
+ 'verbose_name': '直播间信息', |
|
97 |
+ 'verbose_name_plural': '直播间信息', |
|
98 |
+ }, |
|
99 |
+ ), |
|
100 |
+ migrations.CreateModel( |
|
101 |
+ name='RoomOrderInfo', |
|
102 |
+ fields=[ |
|
103 |
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
104 |
+ ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')), |
|
105 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
106 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
107 |
+ ('order_id', shortuuidfield.fields.ShortUUIDField(blank=True, editable=False, help_text='商品ID', max_length=22, unique=True)), |
|
108 |
+ ('user_id', models.CharField(db_index=True, help_text='用户唯一标识', max_length=32, unique=True, verbose_name='user_id')), |
|
109 |
+ ('room_id', models.CharField(db_index=True, help_text='房间唯一标识', max_length=32, unique=True, verbose_name='room_id')), |
|
110 |
+ ('anchor_id', models.CharField(blank=True, help_text='主播唯一标识', max_length=32, unique=True, verbose_name='anchor_id')), |
|
111 |
+ ('goods_id', models.CharField(blank=True, help_text='商品ID', max_length=32, unique=True, verbose_name='goods_id')), |
|
112 |
+ ('share_openid', models.CharField(blank=True, help_text='转发用户 openid', max_length=32, unique=True, verbose_name='share_openid')), |
|
113 |
+ ('amount', models.IntegerField(default=0, help_text='数量', verbose_name='amount')), |
|
114 |
+ ('name', models.CharField(blank=True, help_text='姓名', max_length=255, null=True, verbose_name='name')), |
|
115 |
+ ('phone', models.CharField(blank=True, help_text='电话', max_length=255, null=True, verbose_name='phone')), |
|
116 |
+ ('address', models.CharField(blank=True, help_text='地址', max_length=255, null=True, verbose_name='address')), |
|
117 |
+ ('tracking_number', models.CharField(blank=True, help_text='快递单号', max_length=255, null=True, verbose_name='tracking_number')), |
|
118 |
+ ('has_send_template_message', models.BooleanField(db_index=True, default=True, help_text='是否已发送模版消息', verbose_name='has_send_template_message')), |
|
119 |
+ ('prepay_id', models.CharField(blank=True, help_text='预支付交易会话标识', max_length=64, null=True, verbose_name='prepay_id')), |
|
120 |
+ ('transaction_id', models.CharField(blank=True, help_text='交易单号', max_length=32, null=True, verbose_name='transaction_id')), |
|
121 |
+ ('body', models.CharField(blank=True, help_text='商品描述', max_length=255, null=True, verbose_name='body')), |
|
122 |
+ ('total_fee', models.IntegerField(default=0, help_text='总金额', verbose_name='total_fee')), |
|
123 |
+ ('trade_type', models.CharField(blank=True, help_text='支付方式', max_length=255, null=True, verbose_name='trade_type')), |
|
124 |
+ ('pay_status', models.IntegerField(choices=[(0, '待支付'), (1, '已支付'), (2, '已失败')], db_index=True, default=0, help_text='支付状态', verbose_name='pay_status')), |
|
125 |
+ ('paid_at', models.DateTimeField(blank=True, help_text='支付时间', null=True, verbose_name='paid_at')), |
|
126 |
+ ('reback_status', models.BooleanField(db_index=True, default=False, help_text='退款状态', verbose_name='reback_status')), |
|
127 |
+ ('reback_at', models.DateTimeField(blank=True, help_text='退款时间', null=True, verbose_name='reback_at')), |
|
128 |
+ ('unifiedorder_result', models.TextField(blank=True, help_text='统一下单结果', null=True, verbose_name='unifiedorder_result')), |
|
129 |
+ ('notify_msg', models.TextField(blank=True, help_text='回调信息', null=True, verbose_name='notify_msg')), |
|
130 |
+ ], |
|
131 |
+ options={ |
|
132 |
+ 'verbose_name': '直播间订单', |
|
133 |
+ 'verbose_name_plural': '直播间订单', |
|
134 |
+ }, |
|
135 |
+ ), |
|
136 |
+ ] |
@@ -0,0 +1,24 @@ |
||
1 |
+# Generated by Django 2.2.12 on 2020-05-15 15:21 |
|
2 |
+ |
|
3 |
+from django.db import migrations, models |
|
4 |
+import shortuuidfield.fields |
|
5 |
+ |
|
6 |
+ |
|
7 |
+class Migration(migrations.Migration): |
|
8 |
+ |
|
9 |
+ dependencies = [ |
|
10 |
+ ('live', '0001_initial'), |
|
11 |
+ ] |
|
12 |
+ |
|
13 |
+ operations = [ |
|
14 |
+ migrations.AlterField( |
|
15 |
+ model_name='roomorderinfo', |
|
16 |
+ name='goods_id', |
|
17 |
+ field=models.CharField(blank=True, help_text='商品唯一标识', max_length=32, unique=True, verbose_name='goods_id'), |
|
18 |
+ ), |
|
19 |
+ migrations.AlterField( |
|
20 |
+ model_name='roomorderinfo', |
|
21 |
+ name='order_id', |
|
22 |
+ field=shortuuidfield.fields.ShortUUIDField(blank=True, editable=False, help_text='订单唯一标识', max_length=22, unique=True), |
|
23 |
+ ), |
|
24 |
+ ] |
@@ -0,0 +1,53 @@ |
||
1 |
+# Generated by Django 2.2.12 on 2020-05-15 15:23 |
|
2 |
+ |
|
3 |
+from django.db import migrations, models |
|
4 |
+ |
|
5 |
+ |
|
6 |
+class Migration(migrations.Migration): |
|
7 |
+ |
|
8 |
+ dependencies = [ |
|
9 |
+ ('live', '0002_auto_20200515_2321'), |
|
10 |
+ ] |
|
11 |
+ |
|
12 |
+ operations = [ |
|
13 |
+ migrations.AlterField( |
|
14 |
+ model_name='roomgoodsinfo', |
|
15 |
+ name='anchor_id', |
|
16 |
+ field=models.CharField(blank=True, help_text='主播唯一标识', max_length=32, verbose_name='anchor_id'), |
|
17 |
+ ), |
|
18 |
+ migrations.AlterField( |
|
19 |
+ model_name='roomgoodsinfo', |
|
20 |
+ name='goods_id', |
|
21 |
+ field=models.CharField(blank=True, help_text='商品ID', max_length=32, verbose_name='goods_id'), |
|
22 |
+ ), |
|
23 |
+ migrations.AlterField( |
|
24 |
+ model_name='roominfo', |
|
25 |
+ name='anchor_id', |
|
26 |
+ field=models.CharField(help_text='主播唯一标识', max_length=32, verbose_name='anchor_id'), |
|
27 |
+ ), |
|
28 |
+ migrations.AlterField( |
|
29 |
+ model_name='roomorderinfo', |
|
30 |
+ name='anchor_id', |
|
31 |
+ field=models.CharField(blank=True, help_text='主播唯一标识', max_length=32, verbose_name='anchor_id'), |
|
32 |
+ ), |
|
33 |
+ migrations.AlterField( |
|
34 |
+ model_name='roomorderinfo', |
|
35 |
+ name='goods_id', |
|
36 |
+ field=models.CharField(blank=True, help_text='商品唯一标识', max_length=32, verbose_name='goods_id'), |
|
37 |
+ ), |
|
38 |
+ migrations.AlterField( |
|
39 |
+ model_name='roomorderinfo', |
|
40 |
+ name='room_id', |
|
41 |
+ field=models.CharField(db_index=True, help_text='房间唯一标识', max_length=32, verbose_name='room_id'), |
|
42 |
+ ), |
|
43 |
+ migrations.AlterField( |
|
44 |
+ model_name='roomorderinfo', |
|
45 |
+ name='share_openid', |
|
46 |
+ field=models.CharField(blank=True, help_text='转发用户 openid', max_length=32, verbose_name='share_openid'), |
|
47 |
+ ), |
|
48 |
+ migrations.AlterField( |
|
49 |
+ model_name='roomorderinfo', |
|
50 |
+ name='user_id', |
|
51 |
+ field=models.CharField(db_index=True, help_text='用户唯一标识', max_length=32, verbose_name='user_id'), |
|
52 |
+ ), |
|
53 |
+ ] |
@@ -0,0 +1,35 @@ |
||
1 |
+# Generated by Django 2.2.12 on 2020-05-18 15:23 |
|
2 |
+ |
|
3 |
+from django.db import migrations, models |
|
4 |
+import django_models_ext.fileext |
|
5 |
+import simditor.fields |
|
6 |
+ |
|
7 |
+ |
|
8 |
+class Migration(migrations.Migration): |
|
9 |
+ |
|
10 |
+ dependencies = [ |
|
11 |
+ ('live', '0003_auto_20200515_2323'), |
|
12 |
+ ] |
|
13 |
+ |
|
14 |
+ operations = [ |
|
15 |
+ migrations.RemoveField( |
|
16 |
+ model_name='roominfo', |
|
17 |
+ name='anchor_img', |
|
18 |
+ ), |
|
19 |
+ migrations.AddField( |
|
20 |
+ model_name='anchorinfo', |
|
21 |
+ name='anchor_intro', |
|
22 |
+ field=simditor.fields.RichTextField(blank=True, help_text='主播介绍', verbose_name='anchor_intro'), |
|
23 |
+ ), |
|
24 |
+ migrations.AddField( |
|
25 |
+ model_name='roominfo', |
|
26 |
+ name='share_img', |
|
27 |
+ field=models.ImageField(default='dd', help_text='分享卡片图片', upload_to=django_models_ext.fileext.upload_path, verbose_name='share_img'), |
|
28 |
+ preserve_default=False, |
|
29 |
+ ), |
|
30 |
+ migrations.AlterField( |
|
31 |
+ model_name='anchorinfo', |
|
32 |
+ name='anchor_avatar', |
|
33 |
+ field=models.ImageField(help_text='主播头像', upload_to=django_models_ext.fileext.upload_path, verbose_name='anchor_avatar'), |
|
34 |
+ ), |
|
35 |
+ ] |
@@ -0,0 +1,217 @@ |
||
1 |
+from django.db import models |
|
2 |
+from django.utils.translation import ugettext_lazy as _ |
|
3 |
+from django_models_ext import BaseModelMixin, upload_file_path, upload_file_url, upload_path |
|
4 |
+from jsonfield import JSONField |
|
5 |
+from shortuuidfield import ShortUUIDField |
|
6 |
+from TimeConvert import TimeConvert as tc |
|
7 |
+ |
|
8 |
+from account.models import UserInfo |
|
9 |
+from simditor.fields import RichTextField |
|
10 |
+ |
|
11 |
+class AnchorInfo(BaseModelMixin): |
|
12 |
+ anchor_id = ShortUUIDField(_('anchor_id'), max_length=32, blank=True, help_text='主播唯一标识', unique=True) |
|
13 |
+ # 微信相关 |
|
14 |
+ unionid = models.CharField(_('unionid'), max_length=32, blank=True, help_text='微信 Unionid', unique=True) |
|
15 |
+ openid = models.CharField(_('openid'), max_length=32, blank=True, help_text='微信 Openid', unique=True) |
|
16 |
+ # 真实相关 |
|
17 |
+ anchor_name = models.CharField(_('anchor_name'), max_length=255, blank=True, help_text='主播姓名', db_index=True) |
|
18 |
+ anchor_avatar = models.ImageField(_('anchor_avatar'), upload_to=upload_path, help_text='主播头像') |
|
19 |
+ anchor_intro = RichTextField(_('anchor_intro'), blank=True, help_text='主播介绍') |
|
20 |
+ |
|
21 |
+ class Meta: |
|
22 |
+ verbose_name = _('主播信息') |
|
23 |
+ verbose_name_plural = _('主播信息') |
|
24 |
+ |
|
25 |
+ def __unicode__(self): |
|
26 |
+ return self.pk |
|
27 |
+ |
|
28 |
+ @property |
|
29 |
+ def anchor_avatar_path(self): |
|
30 |
+ return upload_file_path(self.anchor_avatar) |
|
31 |
+ |
|
32 |
+ @property |
|
33 |
+ def anchor_avatar_url(self): |
|
34 |
+ return upload_file_url(self.anchor_avatar) |
|
35 |
+ |
|
36 |
+ |
|
37 |
+class RoomInfo(BaseModelMixin): |
|
38 |
+ room_id = models.CharField(_('anchor_id'), max_length=32, help_text='房间唯一标识', db_index=True, unique=True) |
|
39 |
+ name = models.CharField(_('name'), max_length=255, blank=True, help_text='直播房间名', db_index=True) |
|
40 |
+ live_status = models.IntegerField(_('live_status'), help_text='直播状态', db_index=True) |
|
41 |
+ start_time = models.IntegerField(_('start_time'), help_text='直播计划开始时间', db_index=True) |
|
42 |
+ end_time = models.IntegerField(_('end_time'), help_text='直播计划结束时间', db_index=True) |
|
43 |
+ cover_img = models.ImageField(_('cover_img'), upload_to=upload_path, help_text='直播间背景墙') |
|
44 |
+ anchor_name = models.CharField(_('anchor_name'), blank=True, max_length=255, help_text='主播名称', db_index=True) |
|
45 |
+ share_img = models.ImageField(_('share_img'), upload_to=upload_path, help_text='分享卡片图片') |
|
46 |
+ |
|
47 |
+ anchor_id = models.CharField(_('anchor_id'), max_length=32, help_text='主播唯一标识') |
|
48 |
+ |
|
49 |
+ # "goods": [ |
|
50 |
+ # { |
|
51 |
+ # "cover_img": "http://mmbiz.qpic.cn/mmbiz_png/FVribAGdErI2PmyST9ZM0JLbNM48I7TH2FlrwYOlnYqGaej8qKubG1EvK0QIkkwqvicrYTzVtjKmSZSeY5ianc3mw/0?wx_fmt=png", |
|
52 |
+ # "url": "pages/index/index.html", |
|
53 |
+ # "price": 1100, |
|
54 |
+ # "name": "fdgfgf" |
|
55 |
+ # } |
|
56 |
+ # ], |
|
57 |
+ goods = JSONField(_('goods'), blank=True, default=[], help_text='商品销售信息') |
|
58 |
+ |
|
59 |
+ class Meta: |
|
60 |
+ verbose_name = _('直播间信息') |
|
61 |
+ verbose_name_plural = _('直播间信息') |
|
62 |
+ |
|
63 |
+ def __unicode__(self): |
|
64 |
+ return self.pk |
|
65 |
+ |
|
66 |
+ @property |
|
67 |
+ def cover_img_path(self): |
|
68 |
+ return upload_file_path(self.cover_img) |
|
69 |
+ |
|
70 |
+ @property |
|
71 |
+ def cover_img_url(self): |
|
72 |
+ return upload_file_url(self.cover_img) |
|
73 |
+ |
|
74 |
+ @property |
|
75 |
+ def share_img_path(self): |
|
76 |
+ return upload_file_path(self.share_img) |
|
77 |
+ |
|
78 |
+ @property |
|
79 |
+ def share_img_url(self): |
|
80 |
+ return upload_file_url(self.share_img) |
|
81 |
+ |
|
82 |
+ @property |
|
83 |
+ def anchorData(self): |
|
84 |
+ return { |
|
85 |
+ 'room_id': self.room_id, |
|
86 |
+ 'name': self.name, |
|
87 |
+ 'live_status': self.live_status, |
|
88 |
+ 'cover_img': self.cover_img_url, |
|
89 |
+ 'share_img': self.share_img_url, |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ |
|
93 |
+ |
|
94 |
+class liveGoodsInfo(BaseModelMixin): |
|
95 |
+ goods_id = ShortUUIDField(_('goods_id'), max_length=32, blank=True, help_text='商品ID', unique=True) |
|
96 |
+ |
|
97 |
+ wx_goods_id = models.CharField(_('wx_goods_id'), max_length=255, blank=True, help_text='微信商品ID', db_index=True) |
|
98 |
+ audit_id = models.CharField(_('anchor_name'), max_length=255, blank=True, help_text='审核单ID', db_index=True) |
|
99 |
+ audit_status = models.IntegerField(_('audit_status'), default=0, blank=True, help_text='审核状态', db_index=True) |
|
100 |
+ |
|
101 |
+ goods_img = models.ImageField(_('goods_img'), upload_to=upload_path, help_text='商品图') |
|
102 |
+ |
|
103 |
+ # { |
|
104 |
+ # "goodsInfo": { |
|
105 |
+ # "coverImgUrl": "ZuYVNKk9sMP1X4m7FXdcDCKra251KDZTjS502UTV7gwalgLZXcrOhG6oNYX6c7AR", |
|
106 |
+ # "name":"TIT茶杯", |
|
107 |
+ # "priceType":1, |
|
108 |
+ # "price":"111", |
|
109 |
+ # "price2":"", |
|
110 |
+ # "url":"pages/index/index" |
|
111 |
+ # } |
|
112 |
+ # } |
|
113 |
+ coverImgUrl = models.CharField(_('anchor_name'), max_length=255, blank=True, help_text='微信mediaID', db_index=True) |
|
114 |
+ name = models.CharField(_('name'), max_length=34, help_text='商品', blank=True, db_index=True) |
|
115 |
+ |
|
116 |
+ # 价格类型,1:一口价,2:价格区间,3:显示折扣价;1:一口价,只需要传入price,price2不传;2:价格区间,price字段为左边界,price2字段为右边界,price和price2必传。3:折扣价,price字段为原价,price2字段为现价, price和price2必传 |
|
117 |
+ price_type = models.IntegerField(_('price_type'), help_text='价格类型', db_index=True) |
|
118 |
+ price = models.IntegerField(_('price'), help_text='price') |
|
119 |
+ price2 = models.IntegerField(_('price2'), help_text='price2') |
|
120 |
+ url = models.CharField(_('url'), max_length=255, blank=True, help_text='小程序商品路径', db_index=True) |
|
121 |
+ |
|
122 |
+ class Meta: |
|
123 |
+ verbose_name = _('直播商品库') |
|
124 |
+ verbose_name_plural = _('直播商品库') |
|
125 |
+ |
|
126 |
+ def __unicode__(self): |
|
127 |
+ return self.pk |
|
128 |
+ |
|
129 |
+ @property |
|
130 |
+ def goods_img_path(self): |
|
131 |
+ return upload_file_path(self.goods_img) |
|
132 |
+ |
|
133 |
+ @property |
|
134 |
+ def goods_img_url(self): |
|
135 |
+ return upload_file_url(self.goods_img) |
|
136 |
+ |
|
137 |
+ |
|
138 |
+ |
|
139 |
+class RoomGoodsInfo(BaseModelMixin): |
|
140 |
+ room_id = models.CharField(_('room_id'), max_length=32, help_text='房间唯一标识', db_index=True, unique=True) |
|
141 |
+ anchor_id = models.CharField(_('anchor_id'), max_length=32, blank=True, help_text='主播唯一标识') |
|
142 |
+ goods_id = models.CharField(_('goods_id'), max_length=32, blank=True, help_text='商品ID') |
|
143 |
+ inventory = models.IntegerField(_('inventory'), default=0, help_text='直播间库存数量') |
|
144 |
+ sale_infos = JSONField(_('sale_infos'), blank=True, default=[], help_text='直播间商品销售信息') |
|
145 |
+ |
|
146 |
+ class Meta: |
|
147 |
+ verbose_name = _('直播间商品信息') |
|
148 |
+ verbose_name_plural = _('直播间商品信息') |
|
149 |
+ |
|
150 |
+ def __unicode__(self): |
|
151 |
+ return self.pk |
|
152 |
+ |
|
153 |
+class RoomOrderInfo(BaseModelMixin): |
|
154 |
+ """ |
|
155 |
+ # Trade State of Wechat Query |
|
156 |
+ SUCCESS ——— 支付成功 |
|
157 |
+ REFUND ——— 转入退款 |
|
158 |
+ NOTPAY ——— 未支付 |
|
159 |
+ CLOSED ——— 已关闭 |
|
160 |
+ REVOKED ——— 已撤销(刷卡支付) |
|
161 |
+ USERPAYING ——— 用户支付中 |
|
162 |
+ PAYERROR ——— 支付失败(其他原因,如银行返回失败) |
|
163 |
+ """ |
|
164 |
+ |
|
165 |
+ WAITING_PAY = 0 |
|
166 |
+ PAID = 1 |
|
167 |
+ FAIL = 2 |
|
168 |
+ # DELETED = 9 |
|
169 |
+ |
|
170 |
+ PAY_STATUS = ( |
|
171 |
+ (WAITING_PAY, '待支付'), |
|
172 |
+ (PAID, '已支付'), |
|
173 |
+ (FAIL, '已失败'), |
|
174 |
+ # (DELETED, '已删除'), |
|
175 |
+ ) |
|
176 |
+ |
|
177 |
+ order_id = ShortUUIDField(_('order_id'), max_length=32, blank=True, help_text='订单唯一标识', unique=True) |
|
178 |
+ user_id = models.CharField(_('user_id'), max_length=32, help_text='用户唯一标识', db_index=True) |
|
179 |
+ room_id = models.CharField(_('room_id'), max_length=32, help_text='房间唯一标识', db_index=True) |
|
180 |
+ anchor_id = models.CharField(_('anchor_id'), max_length=32, blank=True, help_text='主播唯一标识') |
|
181 |
+ goods_id = models.CharField(_('goods_id'), max_length=32, blank=True, help_text='商品唯一标识') |
|
182 |
+ share_openid = models.CharField(_('share_openid'), max_length=32, blank=True, help_text='转发用户 openid') |
|
183 |
+ |
|
184 |
+ amount = models.IntegerField(_('amount'), default=0, help_text='数量') |
|
185 |
+ |
|
186 |
+ name = models.CharField(_('name'), max_length=255, blank=True, null=True, help_text='姓名') |
|
187 |
+ phone = models.CharField(_('phone'), max_length=255, blank=True, null=True, help_text='电话') |
|
188 |
+ address = models.CharField(_('address'), max_length=255, blank=True, null=True, help_text='地址') |
|
189 |
+ |
|
190 |
+ tracking_number = models.CharField(_('tracking_number'), max_length=255, blank=True, null=True, help_text='快递单号') |
|
191 |
+ has_send_template_message = models.BooleanField(_('has_send_template_message'), default=True, help_text='是否已发送模版消息', db_index=True) |
|
192 |
+ |
|
193 |
+ prepay_id = models.CharField(_('prepay_id'), max_length=64, blank=True, null=True, help_text='预支付交易会话标识') |
|
194 |
+ transaction_id = models.CharField(_('transaction_id'), max_length=32, blank=True, null=True, help_text='交易单号') |
|
195 |
+ |
|
196 |
+ body = models.CharField(_('body'), max_length=255, blank=True, null=True, help_text='商品描述') |
|
197 |
+ total_fee = models.IntegerField(_('total_fee'), default=0, help_text='总金额') |
|
198 |
+ |
|
199 |
+ trade_type = models.CharField(_('trade_type'), max_length=255, blank=True, null=True, help_text='支付方式') |
|
200 |
+ |
|
201 |
+ pay_status = models.IntegerField(_('pay_status'), choices=PAY_STATUS, default=WAITING_PAY, help_text='支付状态', db_index=True) |
|
202 |
+ paid_at = models.DateTimeField(_('paid_at'), blank=True, null=True, help_text=_('支付时间')) |
|
203 |
+ |
|
204 |
+ reback_status = models.BooleanField(_('reback_status'), default=False, help_text='退款状态', db_index=True) |
|
205 |
+ reback_at = models.DateTimeField(_('reback_at'), blank=True, null=True, help_text=_('退款时间')) |
|
206 |
+ |
|
207 |
+ # 微信统一下单 |
|
208 |
+ unifiedorder_result = models.TextField(_('unifiedorder_result'), blank=True, null=True, help_text=_('统一下单结果')) |
|
209 |
+ # 微信支付回调 |
|
210 |
+ notify_msg = models.TextField(_('notify_msg'), blank=True, null=True, help_text='回调信息') |
|
211 |
+ |
|
212 |
+ class Meta: |
|
213 |
+ verbose_name = _('直播间订单') |
|
214 |
+ verbose_name_plural = _('直播间订单') |
|
215 |
+ |
|
216 |
+ def __unicode__(self): |
|
217 |
+ return self.pk |
@@ -0,0 +1,3 @@ |
||
1 |
+from django.test import TestCase |
|
2 |
+ |
|
3 |
+# Create your tests here. |
@@ -0,0 +1,248 @@ |
||
1 |
+from django.shortcuts import render |
|
2 |
+from django_query import get_query_value |
|
3 |
+from django.db import transaction |
|
4 |
+from django_response import response |
|
5 |
+from django.shortcuts import HttpResponse |
|
6 |
+from django_logit import logit |
|
7 |
+from pywe_exception import WeChatPayException |
|
8 |
+from pywe_pay import WeChatPay |
|
9 |
+from pywe_pay_notify import check_pay_notify |
|
10 |
+from pywe_response import WXPAY_NOTIFY_FAIL, WXPAY_NOTIFY_SUCCESS |
|
11 |
+from TimeConvert import TimeConvert as tc |
|
12 |
+ |
|
13 |
+from django.conf import settings |
|
14 |
+ |
|
15 |
+from live.models import liveGoodsInfo, RoomGoodsInfo, RoomOrderInfo, RoomInfo, AnchorInfo |
|
16 |
+from account.models import UserInfo |
|
17 |
+ |
|
18 |
+from utils.error.errno_utils import OrderStatusCode, UserStatusCode |
|
19 |
+ |
|
20 |
+WECHAT = settings.WECHAT |
|
21 |
+ |
|
22 |
+def room_goods_detail(request): |
|
23 |
+ goods_id = get_query_value(request, 'goods_id', '') |
|
24 |
+ room_id = get_query_value(request, 'room_id', '') |
|
25 |
+ |
|
26 |
+ # 校验直播间和商品 |
|
27 |
+ try: |
|
28 |
+ room_goods_info = RoomGoodsInfo.objects.get(goods_id=goods_id, room_id=room_id) |
|
29 |
+ except: |
|
30 |
+ return response() |
|
31 |
+ |
|
32 |
+ try: |
|
33 |
+ goods_info = liveGoodsInfo.objects.get(goods_id=goods_id) |
|
34 |
+ except: |
|
35 |
+ return response() |
|
36 |
+ |
|
37 |
+ return response(200, 'Get Room Goods Detail Success', '获取直播间商品成功', data={ |
|
38 |
+ 'goods_info': { |
|
39 |
+ 'goods_img': goods_info.goods_img_url, |
|
40 |
+ 'name': goods_info.name, |
|
41 |
+ 'price_type': goods_info.price_type, |
|
42 |
+ 'price': goods_info.price, |
|
43 |
+ 'price2': goods_info.price2, |
|
44 |
+ 'inventory': room_goods_info.inventory, |
|
45 |
+ }, |
|
46 |
+ 'anchor_id': room_goods_info.anchor_id, |
|
47 |
+ }) |
|
48 |
+ |
|
49 |
+WECHAT = settings.WECHAT |
|
50 |
+ |
|
51 |
+def room_anchor_details(request): |
|
52 |
+ room_id = request.POST.get('room_id', '') |
|
53 |
+ |
|
54 |
+ try: |
|
55 |
+ room = RoomInfo.objects.get(room_id=room_id) |
|
56 |
+ except: |
|
57 |
+ return response() |
|
58 |
+ |
|
59 |
+ try: |
|
60 |
+ anchor = AnchorInfo.objects.get(anchor_id=room.anchor_id) |
|
61 |
+ except: |
|
62 |
+ return response() |
|
63 |
+ |
|
64 |
+ rooms = RoomInfo.objects.get(anchor_id=anchor_id) |
|
65 |
+ rooms = [room.anchorData for room in rooms] |
|
66 |
+ |
|
67 |
+ return response(200, 'Get Room Anchor Details Success', '获取主播详情成功', data={ |
|
68 |
+ 'anchor': { |
|
69 |
+ 'anchor_id': anchor.anchor_id, |
|
70 |
+ 'anchor_name': anchor.anchor_name, |
|
71 |
+ 'anchor_avatar': anchor.anchor_avatar_url, |
|
72 |
+ 'anchor_intro': anchor.anchor_intro |
|
73 |
+ }, |
|
74 |
+ 'rooms': rooms |
|
75 |
+ }) |
|
76 |
+ |
|
77 |
+@logit |
|
78 |
+@transaction.atomic |
|
79 |
+def live_order_create(request): |
|
80 |
+ """ 订单创建 """ |
|
81 |
+ user_id = request.POST.get('user_id', '') |
|
82 |
+ room_id = request.POST.get('room_id', '') |
|
83 |
+ anchor_id = request.POST.get('anchor_id', '') |
|
84 |
+ goods_id = request.POST.get('goods_id', '') |
|
85 |
+ share_openid = request.POST.get('share_openid', '') |
|
86 |
+ |
|
87 |
+ name = request.POST.get('name', '') |
|
88 |
+ phone = request.POST.get('phone', '') |
|
89 |
+ address = request.POST.get('address', '') |
|
90 |
+ |
|
91 |
+ amount = int(request.POST.get('amount', 0)) |
|
92 |
+ total_fee = int(request.POST.get('total_fee', 0)) # 总金额,单位分 |
|
93 |
+ |
|
94 |
+ body = request.POST.get('body', '尖货直播') # 商品描述 |
|
95 |
+ |
|
96 |
+ # 用户校验 |
|
97 |
+ try: |
|
98 |
+ user = UserInfo.objects.get(user_id=user_id, status=True) |
|
99 |
+ user.consignee_name = name |
|
100 |
+ user.consignee_phone = phone |
|
101 |
+ user.consignee_address = address |
|
102 |
+ user.save() |
|
103 |
+ except UserInfo.DoesNotExist: |
|
104 |
+ return response(UserStatusCode.USER_NOT_FOUND) |
|
105 |
+ |
|
106 |
+ # 校验直播间和商品 |
|
107 |
+ try: |
|
108 |
+ room_goods_info = RoomGoodsInfo.objects.get(goods_id=goods_id, room_id=room_id, anchor_id=anchor_id) |
|
109 |
+ except: |
|
110 |
+ return response(400001, 'Room Goods Not Found', description='直播间商品不存在') |
|
111 |
+ |
|
112 |
+ # 金额校验 |
|
113 |
+ try: |
|
114 |
+ goods_info = liveGoodsInfo.objects.get(goods_id=goods_id) |
|
115 |
+ if amount * int(goods_info.price) != total_fee: |
|
116 |
+ return response(404091, 'FEE Check Fail', description='金额校验失败') |
|
117 |
+ except: |
|
118 |
+ return response(404091, 'FEE Check Fail', description='金额校验失败') |
|
119 |
+ |
|
120 |
+ # 消库存 |
|
121 |
+ room_goods_info.inventory -= 1 |
|
122 |
+ room_goods_info.save() |
|
123 |
+ |
|
124 |
+ # JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里 |
|
125 |
+ trade_type = 'JSAPI' |
|
126 |
+ |
|
127 |
+ # 根据 trade_type 获取 wechat 配置 |
|
128 |
+ wxcfg = WECHAT.get(trade_type, {}) |
|
129 |
+ # WeChatPay 初始化 |
|
130 |
+ wxpay = WeChatPay(wxcfg.get('appID'), wxcfg.get('apiKey'), wxcfg.get('mchID')) |
|
131 |
+ |
|
132 |
+ # 生成订单 |
|
133 |
+ order = RoomOrderInfo.objects.create( |
|
134 |
+ user_id=user_id, |
|
135 |
+ room_id=room_id, |
|
136 |
+ anchor_id=anchor_id, |
|
137 |
+ goods_id=goods_id, |
|
138 |
+ share_openid=share_openid, |
|
139 |
+ amount=amount, |
|
140 |
+ total_fee=total_fee, |
|
141 |
+ trade_type=trade_type, |
|
142 |
+ name=name, |
|
143 |
+ phone=phone, |
|
144 |
+ address=address, |
|
145 |
+ ) |
|
146 |
+ |
|
147 |
+ try: |
|
148 |
+ prepay_data = wxpay.order.create( |
|
149 |
+ body=body, |
|
150 |
+ notify_url=settings.API_DOMAIN + 'live/pay/notify_url', |
|
151 |
+ out_trade_no=order.order_id, |
|
152 |
+ total_fee=total_fee, |
|
153 |
+ trade_type=trade_type, |
|
154 |
+ openid=user.openid, # 可选,用户在商户appid下的唯一标识。trade_type=JSAPI,此参数必传 |
|
155 |
+ ) |
|
156 |
+ except WeChatPayException as e: |
|
157 |
+ order.unifiedorder_result = e.args |
|
158 |
+ order.save() |
|
159 |
+ return response(OrderStatusCode.UNIFIED_ORDER_FAIL) |
|
160 |
+ |
|
161 |
+ prepay_id = prepay_data.get('prepay_id', '') |
|
162 |
+ order.prepay_id = prepay_id |
|
163 |
+ order.save() |
|
164 |
+ |
|
165 |
+ wxpay_params = wxpay.jsapi.get_jsapi_params(prepay_id) |
|
166 |
+ |
|
167 |
+ |
|
168 |
+ return response(200, 'Order Create Success', '订单创建成功', { |
|
169 |
+ 'order_id': order.order_id, |
|
170 |
+ 'prepay_id': prepay_id, |
|
171 |
+ 'wxpay_params': wxpay_params, |
|
172 |
+ }) |
|
173 |
+ |
|
174 |
+def live_order_cancel(request): |
|
175 |
+ user_id = request.POST.get('user_id', '') |
|
176 |
+ order_id = request.POST.get('order_id', '') |
|
177 |
+ prepay_id = request.POST.get('prepay_id', '') |
|
178 |
+ |
|
179 |
+ try: |
|
180 |
+ order = RoomOrderInfo.objects.get(user_id=user_id, order_id=order_id, prepay_id=prepay_id) |
|
181 |
+ except: |
|
182 |
+ return response(400001, 'Order Not Found', description='直播间订单不存在') |
|
183 |
+ |
|
184 |
+ if order.pay_status == RoomOrderInfo.FAIL: |
|
185 |
+ return response(200, 'Order Cancel Success', '订单取消成功') |
|
186 |
+ |
|
187 |
+ order.pay_status = RoomOrderInfo.FAIL |
|
188 |
+ order.save() |
|
189 |
+ |
|
190 |
+ try: |
|
191 |
+ goods_info = RoomGoodsInfo.objects.get(room_id=order.room_id, goods_id=order.goods_id, anchor_id=order.anchor_id) |
|
192 |
+ goods_info.inventory += order.amount |
|
193 |
+ goods_info.save() |
|
194 |
+ except: |
|
195 |
+ return response(400001, 'Room Goods Not Found', description='直播间商品不存在') |
|
196 |
+ |
|
197 |
+ return response(200, 'Order Cancel Success', '订单取消成功') |
|
198 |
+ |
|
199 |
+def order_paid_success(order): |
|
200 |
+ if order.pay_status == RoomOrderInfo.PAID: |
|
201 |
+ return |
|
202 |
+ |
|
203 |
+ order.pay_status = RoomOrderInfo.PAID |
|
204 |
+ order.paid_at = tc.utc_datetime() |
|
205 |
+ order.save() |
|
206 |
+ |
|
207 |
+ try: |
|
208 |
+ goods_info = RoomGoodsInfo.objects.get(room_id=order.room_id, goods_id=order.goods_id, anchor_id=order.anchor_id) |
|
209 |
+ goods_info.sale_infos += [order.order_id] |
|
210 |
+ goods_info.save() |
|
211 |
+ except: |
|
212 |
+ return |
|
213 |
+ |
|
214 |
+def order_paid_fail(order): |
|
215 |
+ if order.pay_status == RoomGoodsInfo.FAIL: |
|
216 |
+ return |
|
217 |
+ |
|
218 |
+ order.pay_status = RoomGoodsInfo.FAIL |
|
219 |
+ order.save() |
|
220 |
+ |
|
221 |
+ try: |
|
222 |
+ goods_info = RoomGoodsInfo.objects.get(room_id=order.room_id, goods_id=order.goods_id, anchor_id=order.anchor_id) |
|
223 |
+ goods_info.inventory += order.amount |
|
224 |
+ goods_info.save() |
|
225 |
+ except: |
|
226 |
+ return |
|
227 |
+ |
|
228 |
+@logit |
|
229 |
+@transaction.atomic |
|
230 |
+def notify_url_api(request): |
|
231 |
+ """ 支付异步通知回调地址 """ |
|
232 |
+ notify_data, success = check_pay_notify(request.body, wx_configs=settings.WECHAT) |
|
233 |
+ if not success: |
|
234 |
+ return HttpResponse(WXPAY_NOTIFY_FAIL) |
|
235 |
+ |
|
236 |
+ order = RoomOrderInfo.objects.select_for_update().get(order_id=notify_data.get('out_trade_no', ''), status=True) |
|
237 |
+ |
|
238 |
+ order.notify_msg = request.body |
|
239 |
+ order.transaction_id = notify_data.get('transaction_id', '') |
|
240 |
+ order.save() |
|
241 |
+ |
|
242 |
+ result_code = notify_data.get('result_code', '') |
|
243 |
+ if result_code == 'SUCCESS': |
|
244 |
+ live_views.order_paid_success(order) |
|
245 |
+ else: |
|
246 |
+ live_views.order_paid_fail(order) |
|
247 |
+ |
|
248 |
+ return HttpResponse(WXPAY_NOTIFY_SUCCESS) |
@@ -18,8 +18,11 @@ from account.models import UserInfo |
||
18 | 18 |
from goods.models import GoodsInfo, PackGoodsInfo, PackGoodsSaleInfo, PackInfo |
19 | 19 |
from kol.models import KOLInfo |
20 | 20 |
from pay.models import OrderInfo |
21 |
+from live.models import RoomOrderInfo |
|
21 | 22 |
from utils.error.errno_utils import KOLStatusCode, OrderStatusCode, PackGoodsStatusCode, PackStatusCode, UserStatusCode |
22 | 23 |
|
24 |
+from live import views as live_views |
|
25 |
+ |
|
23 | 26 |
|
24 | 27 |
WECHAT = settings.WECHAT |
25 | 28 |
|
@@ -215,19 +218,22 @@ def wx_notify_url_api(request): |
||
215 | 218 |
if not success: |
216 | 219 |
return HttpResponse(WXPAY_NOTIFY_FAIL) |
217 | 220 |
|
221 |
+ #尖货接龙订单 |
|
218 | 222 |
try: |
219 | 223 |
order = OrderInfo.objects.select_for_update().get(order_id=notify_data.get('out_trade_no', ''), status=True) |
220 |
- except OrderInfo.DoesNotExist: |
|
221 |
- return HttpResponse(WXPAY_NOTIFY_FAIL) |
|
224 |
+ order.notify_msg = request.body |
|
225 |
+ order.transaction_id = notify_data.get('transaction_id', '') |
|
226 |
+ order.save() |
|
222 | 227 |
|
223 |
- order.notify_msg = request.body |
|
224 |
- order.transaction_id = notify_data.get('transaction_id', '') |
|
225 |
- order.save() |
|
228 |
+ result_code = notify_data.get('result_code', '') |
|
229 |
+ if result_code == 'SUCCESS': |
|
230 |
+ order_paid_success(order) |
|
231 |
+ else: |
|
232 |
+ order_paid_fail(order) |
|
233 |
+ |
|
234 |
+ return HttpResponse(WXPAY_NOTIFY_SUCCESS) |
|
235 |
+ except: |
|
236 |
+ return HttpResponse(WXPAY_NOTIFY_FAIL) |
|
226 | 237 |
|
227 |
- result_code = notify_data.get('result_code', '') |
|
228 |
- if result_code == 'SUCCESS': |
|
229 |
- order_paid_success(order) |
|
230 |
- else: |
|
231 |
- order_paid_fail(order) |
|
232 | 238 |
|
233 | 239 |
return HttpResponse(WXPAY_NOTIFY_SUCCESS) |